<!DOCTYPE html>
<html>

<head>
    <title>osm buildings demo</title>
    <script type="text/javascript" src="https://unpkg.com/dat.gui@0.7.6/build/dat.gui.min.js"></script>
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/maptalks/dist/maptalks.css">
    <script type="text/javascript" src="https://unpkg.com/maptalks/dist/maptalks.js"></script>
    <script type="text/javascript" src="https://unpkg.com/three@0.138.0/build/three.min.js"></script>
    <script type="text/javascript" src="https://unpkg.com/maptalks.three@latest/dist/maptalks.three.js"></script>
    <script type="text/javascript" src="buildings.js"></script>
    <script type="text/javascript"
        src="https://unpkg.com/three@0.109.0/examples/js/libs/stats.min.js"></script>
    <style>
        html,
        body {
            margin: 0px;
            height: 100%;
            width: 100%;
        }

        #map {
            width: 100%;
            height: 100%;
            background-color: #000;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <script>

        var map = new maptalks.Map("map", {
            "center": [13.413711619774858, 52.533729351798996], "zoom": 16.208199440093424, "pitch": 54.79999999999999,
            "bearing": -176.39999999999998,

            centerCross: true,
            doubleClickZoom: false,
            baseLayer: new maptalks.TileLayer('tile', {
                urlTemplate: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
                subdomains: ['a', 'b', 'c', 'd'],
                attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
            })
        });

        map.on('click', e => {
            console.log(e.coordinate.toArray());
        });

        // features to draw
        var features = [];

        buildings.forEach(function (b) {
            features = features.concat(b.features);
        });

        maptalks.ThreeLayer.prototype.coordinateToXYZ = function (coordinate, height = 0) {
            const z = this.altitudeToVector3(height, height).x;
            return this.coordinateToVector3(coordinate, z);
        }

        // the ThreeLayer to draw buildings
        var threeLayer = new maptalks.ThreeLayer('t', {
            forceRenderOnMoving: true,
            forceRenderOnRotating: true
            // animation: true
        });

        var meshs = [], stats;
        threeLayer.prepareToDraw = function (gl, scene, camera) {
            stats = new Stats();
            stats.domElement.style.zIndex = 100;
            document.getElementById('map').appendChild(stats.domElement);

            // var light = new THREE.DirectionalLight(0xffffff);
            // light.position.set(0, -10, 10).normalize();
            // scene.add(light);

            camera.add(new THREE.PointLight());

            var material = getBuildingsMaterial();
            // material.vertexColors = THREE.VertexColors;
            features.forEach(function (g) {
                var heightPerLevel = 10;
                var levels = g.properties.levels || 1;
                var mesh = threeLayer.toExtrudePolygon(maptalks.GeoJSON.toGeometry(g), {
                    height: levels * heightPerLevel,
                    topColor: '#fff'
                }, material);

                //tooltip test
                mesh.setToolTip(levels * heightPerLevel, {
                    showTimeout: 0,
                    eventsPropagation: true,
                    dx: 10
                });

                //infowindow test
                mesh.setInfoWindow({
                    content: 'hello world,height:' + levels * heightPerLevel,
                    title: 'message',
                    animationDuration: 0,
                    autoOpenOn: false
                });

                meshs.push(mesh);
            });
            threeLayer.addMesh(meshs);
            initSpotLight();
            initGui();
            animation();
            // threeLayer.config('animation', true);
        };
        threeLayer.addTo(map);

        function getBuildingsMaterial(color = 'gray') {
            const width = 256,
                height = 512;
            const canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            let ctx = canvas.getContext('2d');
            ctx.fillStyle = '#070707';

            ctx.fillRect(0, 0, width, 220);
            ctx.fillRect(0, 256, width, 220);

            // var gradient = ctx.createLinearGradient(0, 0, width, 0);
            // gradient.addColorStop("0.0", color);
            // gradient.addColorStop("1.0", 'gray');


            ctx.fillStyle = color;
            // ctx.lineWidth = 40;
            // ctx.shadowColor = shadowColor;
            // ctx.shadowBlur = 70;
            ctx.fillRect(0, 220, width, 36);
            ctx.fillRect(0, 476, width, 36);
            console.log(canvas.toDataURL());
            const texture = new THREE.Texture(canvas);
            texture.needsUpdate = true; //使用贴图时进行更新
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            // texture.repeat.set(0.002, 0.002);
            texture.repeat.set(1, 4);
            const material = new THREE.MeshLambertMaterial({
                map: texture,
                transparent: true
            });
            return material;
        }

        var spotLight, spotLightHelper, vs = [], spotLightHeight = 50, idx = -1;

        function initSpotLight() {

            const lnglat = [13.413713219227247, 52.528798763814706];
            const circle = new maptalks.Circle(lnglat, 1300, {
                numberOfShellPoints: 300
            });
            const shell = circle.getShell();

            vs = shell.map(coordinate => {
                return threeLayer.coordinateToXYZ(coordinate, spotLightHeight);
            });
            spotLight = new THREE.SpotLight('white');
            spotLight.intensity = 100;
            spotLight.angle = 0.10;
            // spotLight.penumbra = 0.05;
            // spotLight.decay = 2;
            spotLight.distance = 20;
            const size = 0.001;
            const cubeGeometry = new THREE.CubeGeometry(size, size, size);
            const cubeMaterial = new THREE.MeshLambertMaterial({
                color: 'yellow'
            });
            const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
            const v1 = threeLayer.coordinateToXYZ(lnglat)
            cube.position.copy(v1);
            spotLight.target = cube;

            threeLayer.addMesh(spotLight);
            threeLayer.addMesh(cube);

            spotLightHelper = new THREE.SpotLightHelper(spotLight);
            threeLayer.addMesh(spotLightHelper);

            const lineMaterial = new THREE.LineBasicMaterial({
                linewidth: 1,
                // color: 0x00ffff,
                // opacity: 0.8,
                transparent: true
            });
            const line = threeLayer.toLine(new maptalks.LineString(shell), { altitude: 0 }, lineMaterial);
            threeLayer.addMesh(line);
        }

        var idxc = -1;
        function animation() {
            threeLayer.redraw();
            stats.update();
            requestAnimationFrame(animation);
            idxc += 0.5;
            const index = Math.round(idxc);

            if (index >= vs.length) {
                idxc = -1;
                idx = -1;
            } else if (index >= 0 && index > idx) {
                idx = index;
                spotLight.position.copy(vs[idx]);

            }
            spotLightHelper.update();
        }

        function initGui() {
            var params = {
                add: true,
                color: '#3e35cf',
                show: true,
                opacity: 1,
                altitude: 0,
                animateShow: animateShow,
                spotLightColor: spotLight.color.getStyle(),
                spotLightIntensity: spotLight.intensity,
                spotLightDistance: spotLight.distance,
                spotLightAngle: spotLight.angle,
                spotLightHeight: spotLightHeight

            };
            var gui = new dat.GUI({
                width: 300
            });
            gui.add(params, 'add').onChange(function () {
                if (params.add) {
                    threeLayer.addMesh(meshs);
                } else {
                    threeLayer.removeMesh(meshs);
                }
            });
            // gui.addColor(params, 'color').name('building color').onChange(function () {
            //     material.color.set(params.color);
            //     meshs.forEach(function (mesh) {
            //         mesh.setSymbol(material);
            //     });
            // });
            gui.add(params, 'opacity', 0, 1).onChange(function () {
                material.opacity = params.opacity;
                meshs.forEach(function (mesh) {
                    mesh.setSymbol(material);
                });
            });
            gui.add(params, 'show').onChange(function () {
                meshs.forEach(function (mesh) {
                    if (params.show) {
                        mesh.show();
                    } else {
                        mesh.hide();
                    }
                });
            });
            gui.add(params, 'altitude', 0, 300).onChange(function () {
                meshs.forEach(function (mesh) {
                    mesh.setAltitude(params.altitude);
                });
            });
            gui.add(params, 'animateShow');

            const spotLightF = gui.addFolder('spotLight');
            spotLightF.open();
            spotLightF.addColor(params, 'spotLightColor').onChange(function () {
                spotLight.color.set(params.spotLightColor);
            });
            spotLightF.add(params, 'spotLightIntensity', 0, 200).onChange(function () {
                spotLight.intensity = params.spotLightIntensity;
            });
            spotLightF.add(params, 'spotLightDistance', 0, 100).onChange(function () {
                spotLight.distance = params.spotLightDistance;
            });
            spotLightF.add(params, 'spotLightAngle', 0, Math.PI).onChange(function () {
                spotLight.angle = params.spotLightAngle;
            });
            spotLightF.add(params, 'spotLightHeight', 0, 600).onChange(function () {
                const z = threeLayer.altitudeToVector3(params.spotLightHeight, params.spotLightHeight).x;
                vs.forEach(v => {
                    v.z = z;
                });

            });
        }

        function animateShow() {
            meshs.forEach(function (mesh) {
                mesh.animateShow({
                    duration: 3000
                });
            });
        }


    </script>
</body>

</html>
